package com.example;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * zookeeper实现分布式锁
 */
public class ZookeeperLock {

    private ZooKeeper zooKeeper;

    private CountDownLatch countDownLatch = new CountDownLatch(1);

    private String path;

    private final static String ROOT = "/lock";

    private final static String NODE = "/lockNode_";

    public ZookeeperLock() {
        try {
            zooKeeper = new ZooKeeper("192.168.228.101:2181", 5000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getState() == Event.KeeperState.SyncConnected) {
                        System.out.println("连接成功");
                        countDownLatch.countDown();
                    }
                }
            });

            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createLock() throws Exception {
        Stat stat = zooKeeper.exists(ROOT, false);
        if (stat == null) {
            zooKeeper.create(ROOT, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }

        path = zooKeeper.create(ROOT + NODE, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("节点 " + path);
    }

    private void attemptLock() throws Exception {
        List<String> children = zooKeeper.getChildren(ROOT, false);
        Collections.sort(children);
        int index = children.indexOf(path.substring(ROOT.length() + 1));
        if (index == 0) {
            System.out.println("获取锁成功");
            return;
        } else {
            String last = children.get(index - 1);

            Stat stat = zooKeeper.exists(ROOT + "/" + last, watcher);
            if (stat == null) {
                attemptLock();
            } else {
                synchronized (watcher) {
                    watcher.wait();
                }
                attemptLock();
            }
        }
    }

    private Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            if (event.getType() == Event.EventType.NodeDeleted) {
                synchronized (this) {
                    notifyAll();
                }
            }
        }
    };


    public void lock() throws Exception {
        createLock();
        attemptLock();
    }



    public void releaseLock() throws Exception {
        zooKeeper.delete(path, -1);
        zooKeeper.close();
    }


    public static void main(String[] args) throws Exception {
        ZookeeperLock lock = new ZookeeperLock();
        lock.createLock();
    }








}



